////////////////////////////////////////////////////////////////////////////
//
//
//    Project     : VideoNet version 1.1.
//    Description : Peer to Peer Video Conferencing over the LAN.
//	  Author      :	Nagareshwar Y Talekar ( nsry2002@yahoo.co.in)
//    Date        : 15-6-2004.
//
//
//    File description : 
//    Name    : convert.cpp
//    Details : Conversion routine from RGB24 to YUV420 & YUV420 to RGB24.
//
/////////////////////////////////////////////////////////////////////////////


#include "convert.h"

static int RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static int RGBYUV01684[256], RGBYUV03316[256];
static int RGBYUV04187[256], RGBYUV00813[256];

int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip)
{
	long i, j = 0, size;
	unsigned char *r, *g, *b;
	unsigned char *y, *u, *v;
	unsigned char *y_buffer;
	unsigned char *sub_u_buf, *sub_v_buf;

	// check to see if x_dim and y_dim are divisible by 2
	if ((x_dim % 2) || (y_dim % 2)) return 1;
	size = x_dim * y_dim;

	// allocate memory
	y_buffer = (unsigned char*)y_out;
	sub_u_buf = (unsigned char*)u_out;
	sub_v_buf = (unsigned char*)v_out;

	b = (unsigned char *)bmp;
	y = y_buffer;
	u = sub_u_buf;
	v = sub_v_buf;

	// convert RGB to YUV
	if (flip) 
	{
	    for (j = 0; j < y_dim; j ++)
	    {
	    	y = y_buffer + (y_dim - j - 1) * x_dim;
	    	u = sub_u_buf + (y_dim/2 - j/2 - 1) * x_dim/2;
	    	v = sub_v_buf + (y_dim/2 - j/2 - 1) * x_dim/2;

		if(!(j % 2))
		{
		    unsigned char* b_ret=b;
		    for (i = 0; i < x_dim/2; i ++) 
		    {
		        y[0]=(unsigned char)
		            ((  RGBYUV02990[b[2]] + RGBYUV05870[b[1]] + RGBYUV01140[b[0]])>>16);
		        y[1]=(unsigned char)
		            ((  RGBYUV02990[b[5]] + RGBYUV05870[b[4]] + RGBYUV01140[b[3]])>>16);
		        y+=2;
		    
		        *u=(unsigned char)
		    	    ((  RGBYUV01684[b[5]] + RGBYUV03316[b[4]] + ((int)(b[3])<<15) + 0x800000)>>16);
		        *v=(unsigned char)
			    ((((int)(b[5])<<15) + RGBYUV04187[b[4]] + RGBYUV00813[b[3]] + 0x800000)>>16);
			u++;
			v++;
			b+=6;
		    }
		}
		else
		    for (i = 0; i < x_dim; i ++) 
		    {
		        *y=(unsigned char)
		    	    ((  RGBYUV02990[b[2]] + RGBYUV05870[b[1]] + RGBYUV01140[b[0]])>>16);
			y++;
			b+=3;
		    }
		}
	} else 
	{
		for (i = 0; i < size; i++)
		{
			g = b + 1;
			r = b + 2;
			*y = (unsigned char)((  RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b])>>16);
			y ++;
			if(!(i%2) && !(j%2))
			{
			    *u = (unsigned char)((  RGBYUV01684[*r] + RGBYUV03316[*g] + ((int)(*b)<<15) + 0x800000)>>16);
			    *v = (unsigned char)((  ((int)(*r)<<15) + RGBYUV04187[*g] + RGBYUV00813[*b] + 0x800000)>>16);
    			    u ++;
			    v ++;
			}
			b += 3;
		}
	}

	return 0;
}


void init_rgb2yuv()
{
	int i;

	for (i = 0; i < 256; i++) RGBYUV02990[i] = (int)(0.2990 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV05870[i] = (int)(0.5870 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV01140[i] = (int)(0.1140 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV01684[i] = -(int)(0.1684 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV03316[i] = -(int)(0.3316 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV04187[i] = -(int)(0.4187 * i * 65536);
	for (i = 0; i < 256; i++) RGBYUV00813[i] = -(int)(0.0813 * i * 65536);
}

